package com.yjzx.util.common.util.batch.mergingLimit;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author guozhi
 * @date 2025/1/13
 * @description PagingView
 */
public class PagingView<T, R> implements NotNullParam {
    T param;
    Function<T, Integer> pageGet;
    BiConsumer<T, Integer> pageSet;
    Function<T, Integer> sizeGet;
    BiConsumer<T, Integer> sizeSet;
    List<PagingSlot<T, R>> list;

    public PagingView(T param, Function<T, Integer> pageGet, BiConsumer<T, Integer> pageSet, Function<T, Integer> sizeGet, BiConsumer<T, Integer> sizeSet, List<PagingSlot<T, R>> list) {
        this.param = param;
        this.pageGet = pageGet;
        this.pageSet = pageSet;
        this.sizeGet = sizeGet;
        this.sizeSet = sizeSet;
        this.list = list;
        check();
    }

    public List<R> toDataPaging() {
        int page = pageGet.apply(param);
        int size = sizeGet.apply(param);
        if (page < 1) {
            page = 1;
            pageSet.accept(param, page);
        }
        if (size < 1) {
            size = 10;
            sizeSet.accept(param, size);
        }
        int dataStart = (page - 1) * size;
        int dataEnd = dataStart + size;
        int length = this.list.size();
        List<Long> totals = new ArrayList<>(length);
        long total = 0;
        for (PagingSlot<T, R> slot : this.list) {
            Long t = slot.getTotalGet().apply(param);
            totals.add(t);
            total += t;
            if (total >= dataEnd) {
                break;
            }
        }
        //获取的数据不存在
        if (total < dataStart) {
            return new ArrayList<>();
        }
        ArrayList<R> list = new ArrayList<>();

        //开始索引
        int end = 0;
        //分页不满一页
        int remainder = 0;
        for (int i = 0; i < totals.size() && page > 0; i++) {
            Long t = totals.get(i);
            end += t;
            long no = t / size;
            if (end >= dataStart) {
                pageSet.accept(param, page);
                List<R> apply = this.list.get(i).dataGet.apply(param);
                if (remainder > 0) {
                    pageSet.accept(param, page + 1);
                    List<R> apply1 = this.list.get(i).dataGet.apply(param);
                    remainder = Math.max(remainder - apply1.size(), 0);
                    list.addAll(
                            Stream.concat(
                                            apply.stream(),
                                            apply1.stream())
                                    .skip(remainder)
                                    .limit(size).collect(Collectors.toList()));
                }
                if (end >= dataEnd) {
                    break;
                }
            }
            remainder += (int) (t % size);
            if (remainder > size) {
                remainder -= size;
                page--;
            }
            page -= no;
        }
        return list;

    }
}
